﻿/*
 * Copyright 2009, Payton Byrd
 * Licensed Under the Microsoft Public License (MS-PL)
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PaytonByrd.Extensions
{
    /// <summary>
    /// Collection of Extension Methods
    /// relating to Reflection operations of
    /// types.
    /// </summary>
    public static class ReflectionExtensions
    {
        #region CreateInstance
        /// <summary>
        /// Creates an instance of the generic
        /// type specified using the parameters
        /// specified.
        /// </summary>
        /// <typeparam name="T">The type to
        /// instantiate.</typeparam>
        /// <param name="type">The System.Type 
        /// being instantiated.</param>
        /// <param name="parameters">The array
        /// of parameters to use when calling 
        /// the constructor.</param>
        /// <returns>An instance of the specified 
        /// type.</returns>
        /// <exception cref="System.Exception" />
        /// <remarks>
        /// If there is not a constructor that 
        /// matches the parameters then an 
        /// <see cref="System.Exception"/> is
        /// thrown.
        /// </remarks>
        /// <example>
        /// typeof(MyObject).CreateInstance(
        ///    new object[] { 1, 3.0M, "Final Parameter" });
        /// </example>
        public static T CreateInstance<T>(
            this System.Type type,
            object[] parameters
            )
        {
            parameters.AssertParameterNotNull(
                "The parameters array must not be null.",
                "parameters");

            T result = default(T);

            List<Type> types = new List<Type>();

            foreach (object parameter in parameters)
            {
                if (parameter.IsNotNull())
                {
                    types.Add(parameter.GetType());
                }
                else
                {
                    types.Add(typeof(object));
                }
            }

            var ctor = 
                type.GetConstructor(types.ToArray());

            if (ctor.IsNotNull())
            {
                result = (T)ctor.Invoke(parameters);
            }
            else
            {
                throw new ArgumentException(
                    "There are no constructors for " +
                    type.FullName + " that " +
                    "match the types provided.");
            }

            return result;
        }

        /// <summary>
        /// Creates an instance of the generic
        /// type specified using the default
        /// constructor.
        /// </summary>
        /// <typeparam name="T">The type to
        /// instantiate.</typeparam>
        /// <param name="type">The System.Type 
        /// being instantiated.</param>
        /// <returns>An instance of the specified 
        /// type.</returns>
        /// <example>
        /// typeof(MyObject).CreateInstance();
        /// </example>
        public static T CreateInstance<T>(
            this System.Type type)
            where T : new()
        {
            return Activator.CreateInstance<T>();
        }
        #endregion
    }
}
